/* 
 * Copyright (c) 2004-2005 Massachusetts Institute of Technology. This code was
 * developed as part of the Haystack (http://haystack.lcs.mit.edu/) research 
 * project at MIT. Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation files (the 
 * "Software"), to deal in the Software without restriction, including without 
 * limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom
 * the Software is furnished to do so, subject to the following conditions: 
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 */
package edu.mit.csail.relo.jdt.parts;

import java.util.ArrayList;
import java.util.List;

import jiggle.Graph;
import jiggle.Vertex;
import jiggle.relo.PointedEdge;

import org.apache.log4j.Logger;
import org.eclipse.draw2d.AbsoluteBendpoint;
import org.eclipse.draw2d.BendpointConnectionRouter;
import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.PolygonDecoration;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Point;

import edu.mit.csail.relo.eclipse.gef.Triangle2;
import edu.mit.csail.relo.graph.GraphAnimation;
import edu.mit.csail.relo.jdt.ReloJDTPlugin;
import edu.mit.csail.relo.modelBridge.Artifact;
import edu.mit.csail.relo.modelBridge.ArtifactRel;
import edu.mit.csail.relo.parts.AbstractReloEditPart;
import edu.mit.csail.relo.parts.ArtifactRelEditPart;
import edu.mit.csail.relo.parts.SideCenteredAnchor;
import edu.mit.csail.relo.store.ReloRdfRepository;


/**
 */
public class MethodCallRelationPart extends ArtifactRelEditPart {
    static final Logger logger = ReloJDTPlugin.getLogger(MethodCallRelationPart.class);

    @Override
    protected jiggle.Edge getEdgeForGraph(Graph graph, Vertex source, Vertex target) {
        return new PointedEdge(graph, source, target, /*vert*/false, /*asc*/true);
    }

	@Override
    protected ConnectionAnchor getSourceConnectionAnchor(AbstractReloEditPart srcEP) {
        return new SideCenteredAnchor(srcEP.getLabelFigure(), SideCenteredAnchor.right);
        //return new SideRestrictedChopboxAnchor(srcEP.getLabelFigure(), SideRestrictedChopboxAnchor.right);
	}

	@Override
    protected ConnectionAnchor getTargetConnectionAnchor(AbstractReloEditPart tgtEP) {
        if (selfCaller)
            return new SideCenteredAnchor(tgtEP.getLabelFigure(), SideCenteredAnchor.right);
        else
            return new SideCenteredAnchor(tgtEP.getLabelFigure(), SideCenteredAnchor.left);
            //return new SideRestrictedChopboxAnchor(tgtEP.getLabelFigure(), SideRestrictedChopboxAnchor.left);
	}

    /* (non-Javadoc)
     * @see edu.mit.csail.relo.parts.ArtifactNavAidsEditPolicy.RelationFigure#getArrow()
     */
    @Override
    public IFigure getArrow() {
        return getArrow(PositionConstants.EAST, new Triangle2());
    }
    
    private boolean selfCaller = false;

    class SelfCallsConnectionRouter extends BendpointConnectionRouter {
        private int distFromTgt;
        public SelfCallsConnectionRouter (int distFromTgt) {
            this.distFromTgt = distFromTgt;
        }
        @Override
        public void route(Connection conn) {
            GraphAnimation.recordInitialState(conn);
            if (!GraphAnimation.playbackState(conn)) {
                List<Object> bendpoints = new ArrayList<Object> (2);
                
                Point startPoint = getStartPoint(conn);
                conn.translateToRelative(startPoint);

                Point endPoint = getEndPoint(conn);
                conn.translateToRelative(endPoint);
                
                int vert = Math.max(startPoint.x, endPoint.x) + distFromTgt;

                bendpoints.add(new AbsoluteBendpoint(vert,startPoint.y));
                bendpoints.add(new AbsoluteBendpoint(vert,endPoint.y));
                
                setConstraint(conn, bendpoints);
                super.route(conn);
            }
        }
    }

    @Override
    protected IFigure createFigure() {
        ArtifactRel rel = this.getArtifactRel();
        ReloRdfRepository repo = getBrowseModel().getRepo();
        if (isSelfCaller(rel, repo)) {
            selfCaller = true;
        } else
            selfCaller = false;
        
        if (selfCaller) {
            PolylineConnection conn = new PolylineConnection();
            conn.setConnectionRouter(new SelfCallsConnectionRouter(15));
            conn.setToolTip(new Label(" " + getRelationLabel() + " "));
            conn.setTargetDecoration(new PolygonDecoration());
            return conn;
        } else
            return super.createFigure();
    }

	private boolean isSelfCaller(ArtifactRel rel, ReloRdfRepository repo) {
		try {
			Artifact src = rel.getSrc();
			Artifact srcParent = src.getParentArtifact(repo);
			Artifact dest = rel.getDest();
			Artifact destParent = dest.getParentArtifact(repo);
			return srcParent != null && srcParent.equals(destParent);
		} catch (Throwable t) {
			logger.error("Unexpected Error", t);
		}
		return false;
	}
}